<?php
/**
 * Description : 格式化日志类
 * @filename   : LogHelper.php
 * @author     : liuqingwei
 * @date       : 2019-07-23
 *
 * @Copyright (c) 2015 liuqingwei
 *
 * vim set ts=4
 */

namespace yii\log;

use Yii;
use yii\base\InvalidConfigException;
use yii\helpers\FileHelper;

class FormatLog extends Target
{
 
    public $logFile;
    
    public $dirMode = 0775;
    
    public $extend;//如果指定扩展类，将会设置为自动降级
    
    public $app_key;
    
    public $reflection = [
        'kafka' => '\yii\log\KafkaLog',
        'redis' => '\yii\log\RedisLog',
    ];
    
    public function init()
    {
        parent::init();
        if ($this->logFile === null)
        {
            $this->logFile = Yii::$app->getRuntimePath() . '/logs/app.log';
        }
        else
        {
            $this->logFile = Yii::getAlias($this->logFile);
        }
        
        $logPath = dirname($this->logFile);
        if (!is_dir($logPath))
        {
            FileHelper::createDirectory($logPath, $this->dirMode, true);
        }
    }
    
    /**
     * 父类方法实现
     */
    public function export()
    {
        
        if (PHP_SAPI == 'cli')
        {
            $text = $this->handleCliMessages($this->messages);
        }
        else
        {
            $text = $this->handleWebMessages($this->messages);
        }
        
        //自动降级
        $this->autoDowngrade($text);
    }
    
    /**
     * 写文件(默认方法)
     * 
     * @param string $text 消息体
     *
     * @throws InvalidConfigException
     */
    public function writeLog($text)
    {
        if (($fp = @fopen($this->logFile, 'a')) === false)
        {
            throw new InvalidConfigException("Unable to append to log file: {$this->logFile}");
        }
    
        @flock($fp, LOCK_EX);
        @fwrite($fp, $text.PHP_EOL);
        @flock($fp, LOCK_UN);
        @fclose($fp);
    
        if ($this->fileMode !== null)
        {
            @chmod($this->logFile, $this->fileMode);
        }
    }
    
    /**
     * 自动降级
     *
     * @param string $text log数据
     *
     * @return mixed
     */
    public function autoDowngrade($text)
    {
        if (empty($this->extend))
        {
            $this->writeLog($text);
            return;
        }
        
        $i = 0;
        $reflection_arr = array_intersect_key($this->reflection,array_flip($this->extend));
        foreach ($reflection_arr as $key=>$value)
        {
            $reflection = new \ReflectionClass($value);
            $extend = $reflection->newInstanceArgs([$this->app_key]);
            $res = $extend->writeLog($text);
            if (empty($res) || $res['code'] != 0)
            {
                if (count($reflection_arr) == (++$i))
                {
                    $this->writeLog($text);
                    break;
                }
            
                continue;
            }
        
            break;
        }
        
        return;
    }
    
    /**
     * 处理消息体(web模式)
     *
     * @param array $messages 消息体
     *
     * @return string
     */
    public function handleWebMessages($messages)
    {
        $msg   = is_array($messages[0][0]) ? json_encode($messages[0][0],JSON_UNESCAPED_UNICODE) : $messages[0][0];
        $post  = !empty($_POST) ? json_encode($_POST,JSON_UNESCAPED_UNICODE) : '';
        $files = !empty($_FILES) ? json_encode($_FILES,JSON_UNESCAPED_UNICODE) : '';
        $request_time = round((microtime(TRUE) - $_SERVER['REQUEST_TIME_FLOAT']) * 1000, 3);
        
        $log = array(
            'level'         => Logger::getLevelName($messages[0][1]),
            'date'          => date("Y-m-d H:i:s"),
            'app'           => $messages[0][2],
            'msg'           => $msg,
            'server_addr'   => $_SERVER['SERVER_ADDR'],
            'remote_addr'   => $_SERVER['REMOTE_ADDR'],
            'host'          => $_SERVER['HTTP_HOST'],
            'log_id'        => \yii\helpers\Html::getUuidCookie(),
            'method'        => $_SERVER['REQUEST_METHOD'],
            'referer'       => $_SERVER['HTTP_REFERER'],
            'status'        => $_SERVER['REDIRECT_STATUS'],
            'uri'           => $_SERVER['REQUEST_URI'],
            'func'          => $_SERVER['REQUEST_URI'],
            'post'          => $post,
            'files'         => $files,
            'response'      => ob_get_contents(),
            'request_time'  => $request_time,
        );
        
        $this->app_key = $messages[0][2];
        $log = json_encode($log,JSON_UNESCAPED_UNICODE);
        return $log;
    }
    
    /**
     * 处理消息体(cli模式)
     *
     * @param array $messages 消息体
     *
     * @return string
     */
    public function handleCliMessages($messages)
    {
        $msg = is_array($messages[2][0]) ? json_encode($messages[2][0],JSON_UNESCAPED_UNICODE) : $messages[2][0];
        $log = array(
            'level'         => Logger::getLevelName($messages[2][1]),
            'date'          => date("Y-m-d H:i:s"),
            'mode'          => 'cli',
            'app'           => $messages[2][2],
            'msg'           => $msg,
        );
        
        $this->app_key = $messages[2][2].'-cli';
        $log = json_encode($log,JSON_UNESCAPED_UNICODE);
        return $log;
    }
    
}